package cn.lijiajia3515.cairo.auth.security.oauth2.resource.server.authentication;

import cn.lijiajia3515.cairo.auth.CairoAuthentication;
import cn.lijiajia3515.cairo.auth.modules.AuthenticationClient;
import cn.lijiajia3515.cairo.domain.CairoAccount;
import cn.lijiajia3515.cairo.security.oauth2.jwt.CairoJwtPrincipal;
import cn.lijiajia3515.cairo.security.oauth2.resource.server.authentication.CairoJwtAuthenticationToken;
import feign.FeignException;
import lombok.Getter;
import lombok.Setter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;

import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 1. oidc 认证 账号+权限
 * 2. client认证(oauth2认证, jwt) client + scope
 * cairo jwt 转换器
 */
public class CairoJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {

	@Getter
	@Setter
	private JwtAuthenticationConverter defaultConverter = new JwtAuthenticationConverter();

	private final AuthenticationClient authenticationClient;

	public CairoJwtAuthenticationConverter(AuthenticationClient authenticationClient) {
		this.authenticationClient = authenticationClient;
	}

	@Override
	public AbstractAuthenticationToken convert(Jwt jwt) {
		try {
			return Optional.ofNullable(jwt.getAudience())
				.flatMap(x -> x.stream().findFirst())
				.map(client -> authenticationClient.authentication("Bearer " + jwt.getTokenValue()))
				.map(auth -> (AbstractAuthenticationToken) new CairoJwtAuthenticationToken(
						new CairoJwtPrincipal(jwt, account(auth)),
						auth.getAuthorities().stream()
							.map(SimpleGrantedAuthority::new)
							.collect(Collectors.toSet())
					)
				)
				.orElse(defaultConverter.convert(jwt));
		} catch (FeignException ex) {
			throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
		}
	}

	public CairoAccount account(CairoAuthentication authentication) {
		return CairoAccount.builder()
			.id(authentication.getId())
			.login(authentication.getLogin())
			.email(authentication.getEmail())
			.phoneNumber(authentication.getPhoneNumber())

			.nickname(authentication.getNickname())
			.avatarUrl(authentication.getAvatarUrl())
			.departments(authentication.getDepartments())
			.roles(authentication.getRoles())

			.build();

	}
}
